﻿using Microsoft.AspNetCore.Http;
using MiniFox.Components;
using MiniFox.Platform.Applications.Auth;
using MiniFox.Platform.Web;
using System.Net.Http.Headers;

namespace MiniFox.Platform.Applications.Web
{
    /// <summary>
    /// 
    /// </summary>
    public static class WebStateExtensions
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public static IAuthStateManagement GetAuthState(this HttpContext httpContext)
        {
            HttpRequest httpRequest = httpContext.Request;

            IAuthStateManagement stateManagement = httpContext.Items[ClientKey.OPEN_AUTH_CONTEXT_KEY] as IAuthStateManagement;
            if (stateManagement == null)
            {
                stateManagement = ComponentFactory.GetComponent<IAuthStateManagement>();
                httpContext.InitStateManagement(stateManagement);

                string? token = string.Empty;

                bool hasValue = httpRequest.Headers.Authorization.Any();
                if (hasValue)
                {
                    var authValue = AuthenticationHeaderValue.Parse(httpRequest.Headers.Authorization);
                    token = authValue.Parameter;//httpRequest.Headers.Authorization.ToString().Replace("Bearer", string.Empty);
                }
                else
                {
                    token = httpRequest.Headers[ClientKey.SECURE_CLIENT_TOKEN];
                }
                if (string.IsNullOrEmpty(token))
                {
                    token = httpRequest.Cookies[ClientKey.SECURE_CLIENT_TOKEN];
                }
                stateManagement.Token = token?.Trim();

                httpContext.Items[ClientKey.OPEN_AUTH_CONTEXT_KEY] = stateManagement;
            }
            return stateManagement;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public static T GetAuthClient<T>(this HttpContext httpContext) where T : AuthorizationClient
        {
            T authClient = httpContext.Items[ClientKey.OPEN_AUTH_CLIENT_KEY] as T;
            if (authClient == null)
            {
                authClient = ComponentFactory.GetComponent<T>(httpContext.GetAuthState());
                httpContext.Items[ClientKey.OPEN_AUTH_CLIENT_KEY] = authClient;
            }
            return authClient;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="httpContext"></param>
        /// <param name="authClient"></param>
        internal static void SetAuthClient<T>(this HttpContext httpContext, T authClient) where T : AuthorizationClient
        {
            httpContext.SetAuthState(authClient.StateManagement);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="stateManagement"></param>
        internal static void SetAuthState(this HttpContext httpContext, IAuthStateManagement stateManagement)
        {
            if (stateManagement.Cleared)
                return;

            var response = httpContext.Response;
            //回写状态，滑动过期
            if (string.IsNullOrEmpty(stateManagement.Token))
            {
                //清除cookie值
                response.Cookies.Delete(ClientKey.SECURE_CLIENT_TOKEN, new CookieOptions
                {
                    Expires = DateTimeOffset.UtcNow.AddDays(-1)
                });
            }
            else
            {
                if (response.Headers.Keys.Contains(ClientKey.SECURE_CLIENT_TOKEN))
                {
                    response.Headers[ClientKey.SECURE_CLIENT_TOKEN] = stateManagement.Token;
                }
                else
                {
                    response.Headers.Append(ClientKey.SECURE_CLIENT_TOKEN, stateManagement.Token);
                }

                var cookieStateExpiration = DateTimeOffset.UtcNow.AddSeconds(stateManagement.CookieStateExpires);
                response.Cookies.Append(ClientKey.SECURE_CLIENT_TOKEN, stateManagement.Token, new CookieOptions
                {
                    Expires = cookieStateExpiration
                });
            }

        }

    }

}
